<template>
  <div class="p-2">
    <a-row :gutter="16">
      <a-col :lg="4" :xs="24">
        <a-card class="general-card" hoverable title="组织查询">
          <a-input-search
            v-model.lazy.trim="deptName"
            :readonly="readonlyFlag"
            allow-clear
            placeholder="请输入组织名称"
            style="margin-bottom: 10px"
            type="text"
            @focus="handleIptClick"
          />
          <a-tree
            v-if="filteredTreeData.length"
            :data="filteredTreeData"
            :field-names="{ key: 'id', title: 'label', children: 'children' }"
            :selected-keys="selectedTreeKeys"
            block-node
            default-expand-all
            default-expanded-all
            show-line
            @select="handleNodeSelect"
          >
            <template #title="nodeData">
              <template v-if="getMatchIndex(nodeData?.label) < 0">
                {{ nodeData?.label }}
              </template>
              <template v-else>
                <span v-html="getHighlightedLabel(nodeData?.label)"></span>
              </template>
            </template>
          </a-tree>
        </a-card>
      </a-col>
      <a-col :lg="20" :xs="24">
        <div class="mb-[10px]">
          <a-card class="general-card" hoverable title="用户查询">
            <a-row>
              <a-col :flex="1">
                <a-form ref="queryFormRef" :model="queryParams" label-align="left" layout="inline">
                  <a-form-item field="userName" label="用户名称">
                    <a-input
                      v-model.trim="queryParams.userName"
                      :style="{ width: '240px' }"
                      allow-clear
                      placeholder="请输入用户名称"
                    >
                      <template #prefix>
                        <icon-search />
                      </template>
                    </a-input>
                  </a-form-item>
                  <a-form-item>
                    <a-space :size="18">
                      <a-button type="primary" @click="handleQuery">
                        <template #icon>
                          <icon-search />
                        </template>
                        查询
                      </a-button>
                      <a-button @click="resetQuery">
                        <template #icon>
                          <icon-refresh />
                        </template>
                        重置
                      </a-button>
                    </a-space>
                  </a-form-item>
                </a-form>
              </a-col>
            </a-row>
            <a-divider style="margin-top: 0" />
            <a-row style="margin-bottom: 16px">
              <a-col :span="12">
                <a-space>
                  <a-button type="primary" @click="handleAdd">新建</a-button>
                  <a-button :disabled="single" status="success" @click="handleUpdate"> 修改</a-button>
                  <a-button :disabled="multiple" status="danger" @click="handleDelete"> 删除</a-button>
                </a-space>
              </a-col>
              <a-col :span="12" style="display: flex; align-items: center; justify-content: end">
                <a-tooltip content="下载">
                  <div class="action-icon">
                    <icon-download size="18" />
                  </div>
                </a-tooltip>
                <a-tooltip content="刷新">
                  <div class="action-icon" @click="handleQuery">
                    <icon-refresh size="18" />
                  </div>
                </a-tooltip>
                <a-dropdown @select="handleSelectDensity">
                  <a-tooltip content="密度">
                    <div class="action-icon">
                      <icon-line-height size="18" />
                    </div>
                  </a-tooltip>
                  <template #content>
                    <a-doption
                      v-for="item in densityList"
                      :key="item.value"
                      :class="{ active: item.value === size }"
                      :value="item.value"
                    >
                      <span>{{ item.name }}</span>
                    </a-doption>
                  </template>
                </a-dropdown>
                <a-tooltip content="列设置">
                  <a-popover position="br" trigger="click" @popup-visible-change="popupVisibleChange">
                    <div class="action-icon">
                      <icon-settings size="18" />
                    </div>
                    <template #content>
                      <div id="tableSetting">
                        <div v-for="(item, index) in showColumns" :key="item.dataIndex" class="setting">
                          <div style="margin-right: 4px; cursor: move">
                            <icon-drag-arrow />
                          </div>
                          <div>
                            <a-checkbox
                              v-model="item.checked"
                              @change="handleChange($event, item as TableColumnData, index)"
                            ></a-checkbox>
                          </div>
                          <div class="title">
                            {{ item.title === "#" ? "序列号" : item.title }}
                          </div>
                        </div>
                      </div>
                    </template>
                  </a-popover>
                </a-tooltip>
              </a-col>
            </a-row>
            <a-table
              v-model:selectedKeys="selectedKeys"
              :bordered="false"
              :columns="cloneColumns as TableColumnData[]"
              :data="userList"
              :loading="loading"
              :pagination="pagination"
              :row-selection="rowSelection"
              :size="size"
              row-key="userId"
              scrollbar
              stripe
              @page-change="onPageChange"
              @page-size-change="onPageSizeChange"
              @selection-change="onSelectChange"
            >
              <template #index="{ rowIndex }">
                {{ rowIndex + 1 + (pagination.pageNum - 1) * pagination.pageSize }}
              </template>
              <template #operations="{ record }">
                <a-space v-if="record.userId !== 1">
                  <a-link :hoverable="false" href="javascript:void(0)" @click="handleUpdate(record)"> 修改</a-link>
                  <a-link :hoverable="false" href="javascript:void(0)" @click="handleResetPwd(record)"> 重置</a-link>
                  <a-link :hoverable="false" href="javascript:void(0)" @click="handleDelete(record)"> 删除</a-link>
                </a-space>
              </template>
            </a-table>
          </a-card>

          <a-modal
            ref="formDialogRef"
            :ok-loading="formLoading"
            :title="dialog.title"
            :visible="dialog.visible"
            cancel-text="取消"
            draggable
            ok-text="保存"
            title-align="start"
            width="650px"
            @cancel="handleCancel"
            @ok="handleOk"
          >
            <a-spin :loading="formDialogLoading" dot>
              <a-form ref="userFormRef" :model="form" :rules="rules" :style="{ width: '610px' }" layout="vertical">
                <a-row :gutter="16">
                  <a-col :span="12">
                    <a-form-item asterisk-position="end" field="userName" label="用户名" required validate-trigger="blur">
                      <a-input v-model.trim="form.userName" allow-clear placeholder="请输入用户名" />
                    </a-form-item>
                  </a-col>
                  <a-col :span="12">
                    <a-form-item asterisk-position="end" field="nickName" label="用户昵称" required validate-trigger="blur">
                      <a-input v-model.trim="form.nickName" allow-clear placeholder="请输入用户昵称" />
                    </a-form-item>
                  </a-col>
                </a-row>
                <a-row :gutter="16">
                  <a-col :span="12">
                    <a-form-item field="phoneNumber" label="手机号码" validate-trigger="blur">
                      <a-input v-model.trim="form.phoneNumber" allow-clear placeholder="请输入手机号码" />
                    </a-form-item>
                  </a-col>
                  <a-col :span="12">
                    <a-form-item field="email" label="邮箱" validate-trigger="blur">
                      <a-input v-model.trim="form.email" allow-clear placeholder="请输入邮箱" />
                    </a-form-item>
                  </a-col>
                </a-row>
                <a-row :gutter="16">
                  <a-col :span="12">
                    <a-form-item field="sex" label="性别" validate-trigger="blur">
                      <a-radio-group v-model="form.sex">
                        <a-radio v-for="dict in sys_user_sex" :value="dict.value">
                          {{ dict.label }}
                        </a-radio>
                      </a-radio-group>
                    </a-form-item>
                  </a-col>
                  <a-col :span="12">
                    <a-form-item asterisk-position="end" field="deptId" label="所属部门" required validate-trigger="blur">
                      <a-tree-select
                        v-model="form.deptId"
                        :data="deptOptions"
                        :field-names="{
                          key: 'id',
                          title: 'label',
                          children: 'children'
                        }"
                        allow-clear
                        placeholder="请选择所属组织"
                      />
                    </a-form-item>
                  </a-col>
                </a-row>
                <a-row :gutter="16">
                  <a-col :span="12">
                    <a-form-item asterisk-position="end" field="roleIds" label="角色" required validate-trigger="blur">
                      <a-select
                        v-model="form.roleIds"
                        :max-tag-count="2"
                        allow-clear
                        allow-search
                        multiple
                        placeholder="请选择角色"
                      >
                        <a-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" />
                      </a-select>
                    </a-form-item>
                  </a-col>
                  <a-col :span="12">
                    <a-form-item field="postIds" label="岗位" validate-trigger="blur">
                      <a-select
                        v-model="form.postIds"
                        :max-tag-count="2"
                        allow-clear
                        allow-search
                        multiple
                        placeholder="请选择岗位"
                      >
                        <a-option
                          v-for="item in postOptions"
                          :key="item.postId"
                          :disabled="item.postStatus == '1'"
                          :label="item.postName"
                          :value="item.postId"
                        />
                      </a-select>
                    </a-form-item>
                  </a-col>
                </a-row>
                <a-row :gutter="16">
                  <a-col :span="12">
                    <a-form-item label="描述" validate-trigger="blur">
                      <a-textarea v-model.trim="form.remark" placeholder="请输入描述信息" />
                    </a-form-item>
                  </a-col>
                  <a-col :span="12">
                    <a-form-item field="postStatus" label="状态" validate-trigger="blur">
                      <a-radio-group v-model="form.userStatus">
                        <a-radio v-for="dict in sys_normal_disable" :value="dict.value">
                          {{ dict.label }}
                        </a-radio>
                      </a-radio-group>
                    </a-form-item>
                  </a-col>
                </a-row>
              </a-form>
            </a-spin>
          </a-modal>

          <!--密码-->
          <a-modal
            :ok-loading="resetPwdLoading"
            :title="title"
            :visible="resetPwdVisible"
            cancel-text="取消"
            draggable
            ok-text="保存"
            title-align="start"
            width="400px"
            @cancel="handleResetPwdCancel"
            @ok="handleResetPwdOk"
          >
            <a-input-password v-model="newPassword" allow-clear placeholder="请输入新的密码">
              <template #prefix>
                <icon-lock />
              </template>
            </a-input-password>
          </a-modal>
        </div>
      </a-col>
    </a-row>
  </div>
</template>

<script lang="ts" name="User" setup>
import useLoading from "@/hooks/useLoading";
import api from "@/api/system/user";
import { DeptVO } from "@/api/system/dept/types";
import { treeSelect } from "@/api/system/dept";
import { UserForm, UserQuery, UserVO } from "@/api/system/user/types";
import cloneDeep from "lodash/cloneDeep";
import { TableColumnData } from "@arco-design/web-vue/es/table/interface";
import { PostVO } from "@/api/system/post/types";
import { RoleVO } from "@/api/system/role/types";
import { Message, Modal } from "@arco-design/web-vue";
import Sortable from "sortablejs";
import * as Regexp from "@/utils/regexp";

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict("sys_normal_disable", "sys_user_sex"));

const showColumns = ref<Column[]>([]);
const queryFormRef = ref<ArcoFormInstance>();
const deptTreeRef = ref<ArcoTreeInstance>();
const userFormRef = ref<ArcoFormInstance>();
const dialog = reactive<DialogOption>({
  visible: false,
  title: ""
});
const formLoading = ref(false);
const resetPwdVisible = ref(false);
const formDialogLoading = ref(false);
const title = ref("");
const resetPwdLoading = ref(false);
const newPassword = ref("");
const selectedKeys = ref([]);
const selectedTreeKeys = ref<Array<string | number>>([]);
const rowSelection = reactive({
  type: "checkbox",
  showCheckedAll: true,
  onlyCurrent: false
});
const single = ref(true);
const multiple = ref(true);
type Column = TableColumnData & { checked?: true };

const readonlyFlag = ref(true);
type SizeProps = "mini" | "small" | "medium" | "large";
const { loading, setLoading } = useLoading(true);
const cloneColumns = ref<Column[]>([]);
const columns = computed<TableColumnData[]>(() => [
  {
    title: "用户编号",
    dataIndex: "userId",
    slotName: "index",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "用户名称",
    dataIndex: "userName",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "用户昵称",
    dataIndex: "nickName",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "组织",
    dataIndex: "deptName",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "手机号码",
    dataIndex: "phoneNumber",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "创建时间",
    dataIndex: "createTime",
    ellipsis: true,
    tooltip: true,
    align: "center"
  },
  {
    title: "操作",
    dataIndex: "operations",
    slotName: "operations",
    align: "center"
  }
]);
const initPassword = ref<string>("");
const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
const size = ref<SizeProps>("medium");
const initFormData: UserForm = {
  userId: undefined,
  deptId: undefined,
  userName: "",
  nickName: undefined,
  password: "",
  phoneNumber: undefined,
  email: undefined,
  sex: "0",
  userStatus: "0",
  remark: "",
  postIds: [],
  roleIds: []
};
const densityList = computed(() => [
  {
    name: "迷你",
    value: "mini"
  },
  {
    name: "偏小",
    value: "small"
  },
  {
    name: "中等",
    value: "medium"
  },
  {
    name: "偏大",
    value: "large"
  }
]);
const initData: PageData<UserForm, UserQuery> = {
  form: { ...initFormData },
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    userName: "",
    userStatus: "",
    deptId: "",
    roleId: ""
  },
  rules: {
    userName: [
      { required: true, message: "用户名称不能为空", trigger: "blur" },
      {
        min: 2,
        max: 20,
        message: "用户名称长度必须介于 2 和 20 之间",
        trigger: "blur"
      }
    ],
    nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
    password: [
      { required: true, message: "用户密码不能为空", trigger: "blur" },
      {
        min: 5,
        max: 20,
        message: "用户密码长度必须介于 5 和 20 之间",
        trigger: "blur"
      },
      {
        required: false,
        pattern: /^[^<>"'|\\]+$/,
        message: "不能包含非法字符：< > \" ' \\\ |",
        trigger: "blur"
      }
    ],
    email: [
      {
        type: "email",
        required: false,
        message: "请输入正确的邮箱地址"
      }
    ],
    phoneNumber: [
      {
        match: Regexp.Phone,
        message: "请输入正确的手机号码"
      }
    ],
    roleIds: [{ required: true, message: "用户角色不能为空", trigger: "blur" }]
  }
};
const data = reactive<PageData<UserForm, UserQuery>>(initData);

const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);

const pagination = ref({
  pageNum: queryParams.value.pageNum,
  pageSize: queryParams.value.pageSize,
  total: 0,
  showTotal: true,
  showPageSize: true
});

const userList = ref<UserVO[]>();
const deptOptions = ref<DeptVO[]>([]);
const deptName = ref("");
const filteredTreeData = ref<DeptVO[]>([]);

const reSetPwdRow = ref<UserVO>(<UserVO>{});

/** 初始化组织数据 */
const initTreeData = async () => {
  // 判断部门的数据是否存在，存在不获取，不存在则获取
  if (deptOptions.value.length === 0) {
    const { data } = await treeSelect();
    deptOptions.value = data;
    filteredTreeData.value = data; // 初始化时设置过滤后的数据
  }
};

/** 查询组织下拉树结构 */
const getTreeSelect = async () => {
  const res = await api.deptTreeSelect();
  deptOptions.value = res.data;
  filteredTreeData.value = res.data; // 获取数据后设置过滤后的数据
};

const getMatchIndex = (title: string) => {
  if (!deptName.value) {
    return -1;
  }
  return title.toLowerCase().indexOf(deptName.value.toLowerCase());
};

const getHighlightedLabel = (label: string) => {
  const index = getMatchIndex(label);
  if (index < 0) return label;
  const beforeMatch = label.substr(0, index);
  const matchText = label.substr(index, deptName.value.length);
  const afterMatch = label.substr(index + deptName.value.length);
  return `${beforeMatch}<span style="color: var(--color-primary-light-4)">${matchText}</span>${afterMatch}`;
};

const handleIptClick = () => {
  readonlyFlag.value = false;
};

const searchData = (keyword: string) => {
  const loop = (data: any[]): any[] => {
    const result: any[] = [];
    data.forEach(item => {
      if (item.label.toLowerCase().includes(keyword.toLowerCase())) {
        result.push({ ...item });
      } else if (item.children) {
        const filterData = loop(item.children);
        if (filterData.length) {
          result.push({ ...item, children: filterData });
        }
      }
    });
    return result;
  };
  return loop(deptOptions.value);
};

const onSelectChange = (rowKeys: (string | number)[]) => {
  multiple.value = !rowKeys.length;
  single.value = rowKeys.length !== 1;
};

const onPageChange = async (page: number) => {
  queryParams.value.pageNum = page;
  await getList();
};

const onPageSizeChange = (pageSize: number) => {
  queryParams.value.pageSize = pageSize;
  getList();
};

/** 节点单击事件 */
const handleNodeSelect = (
  selectedKeys: Array<string | number>,
  data: {
    selected?: boolean;
    selectedNodes: DeptVO[];
    node?: DeptVO;
    e?: Event;
  }
) => {
  selectedTreeKeys.value = selectedKeys;
  queryParams.value.deptId = data.node?.id;
  handleQuery();
};

/** 搜索按钮操作 */
const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
};

/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.value.pageNum = 1;
  queryParams.value.deptId = undefined;
  deptTreeRef.value?.setCurrentKey(undefined);
  selectedTreeKeys.value = [];
  handleQuery();
};

/** 查询用户列表 */
const getList = async () => {
  loading.value = true;
  try {
    const res = await api.listUser(queryParams.value);
    userList.value = res.rows;
    pagination.value.total = res.total;
  } finally {
    loading.value = false;
  }
};

/** 重置密码按钮操作 */
const handleResetPwd = async (row: UserVO) => {
  title.value = '请输入"' + row.userName + '"的新密码';
  resetPwdVisible.value = true;
  Object.assign(reSetPwdRow.value, row);
};

/** 删除按钮操作 */
const handleDelete = async (row?: UserVO) => {
  const userIds = row?.userId ? [row.userId] : selectedKeys.value;
  const desc = row?.userName === undefined ? "当前选中用户编号为 " : " 当前选中用户名称为 ";
  const content = row?.userName === undefined ? userIds.join() : row?.userName;
  Modal.warning({
    titleAlign: "start",
    alignCenter: false,
    hideCancel: false,
    width: "500",
    title: "提示",
    okLoading: loading.value,
    content: () =>
      h("div", null, [desc, h("span", { style: "color: red;font-weight: 700;font-size: 16px" }, content), " 的数据项?"]),
    onBeforeOk: async () => {
      await api.delUser(userIds);
      await getList();
    }
  });
};

// 定义校验规则
const validatePassword = (password: string): string | null => {
  if (password.length < 8) {
    return "密码长度必须至少为8个字符";
  }
  if (!/[A-Z]/.test(password)) {
    return "密码必须包含至少一个大写字母";
  }
  if (!/[a-z]/.test(password)) {
    return "密码必须包含至少一个小写字母";
  }
  if (!/[0-9]/.test(password)) {
    return "密码必须包含至少一个数字";
  }
  if (!/[!@#$%^&*]/.test(password)) {
    return "密码必须包含至少一个特殊字符（!@#$%^&*）";
  }
  return null;
};

const handleResetPwdOk = async () => {
  const password = newPassword.value;
  const validationResult = validatePassword(password);
  try {
    if (!validationResult) {
      resetPwdLoading.value = true;
      await api.resetUserPwd(reSetPwdRow.value.userId, password);
      Message.success("密码重置成功");
      resetPwdVisible.value = false;
    } else {
      Message.error(validationResult);
    }
  } finally {
    resetPwdLoading.value = false;
  }
};

const handleResetPwdCancel = () => {
  resetPwdVisible.value = false;
};

/** 重置操作表单 */
const reset = () => {
  form.value = { ...initFormData };
  userFormRef.value?.resetFields();
};

/**
 * 重置表单
 */
const resetForm = () => {
  userFormRef.value?.resetFields();
  userFormRef.value?.clearValidate();
  form.value.id = undefined;
  form.value.userStatus = "1";
};

/** 修改按钮操作 */
const handleUpdate = async (row?: UserForm) => {
  try {
    reset();
    formDialogLoading.value = true;
    dialog.visible = true;
    dialog.title = "修改用户";
    const userId = row?.userId || selectedKeys.value[0];
    const { data } = await api.getUser(userId);
    await initTreeData();
    Object.assign(form.value, data.sysUserVo);
    postOptions.value = data.posts;
    roleOptions.value = data.roles;
    form.value.postIds = data.postIds;
    form.value.roleIds = data.roleIds;
    form.value.password = "";
  } finally {
    formDialogLoading.value = false;
  }
};

/** 新增按钮操作 */
const handleAdd = async () => {
  try {
    reset();
    formDialogLoading.value = true;
    dialog.visible = true;
    dialog.title = "新增用户";
    const { data } = await api.getUser();
    await initTreeData();
    postOptions.value = data.posts;
    roleOptions.value = data.roles;
    form.value.password = initPassword.value.toString();
  } finally {
    formDialogLoading.value = false;
  }
};

/** 提交按钮 */
const handleOk = () => {
  userFormRef.value?.validate(async (errors: undefined) => {
    if (!errors) {
      formLoading.value = true;
      try {
        form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
        dialog.visible = false;
        await handleQuery();
      } finally {
        formLoading.value = false;
      }
    }
  });
};

/**
 * 关闭用户弹窗
 */
const handleCancel = () => {
  dialog.visible = false;
  resetForm();
};

const handleSelectDensity = (val: string | number | Record<string, any> | undefined, _e: Event) => {
  size.value = val as SizeProps;
};

const exchangeArray = <T extends Array<any>>(array: T, beforeIdx: number, newIdx: number, isDeep = false): T => {
  const newArray = isDeep ? cloneDeep(array) : array;
  if (beforeIdx > -1 && newIdx > -1) {
    // 先替换后面的，然后拿到替换的结果替换前面的
    newArray.splice(beforeIdx, 1, newArray.splice(newIdx, 1, newArray[beforeIdx]).pop());
  }
  return newArray;
};

const popupVisibleChange = (val: boolean) => {
  if (val) {
    nextTick(() => {
      const el = document.getElementById("tableSetting") as HTMLElement;
      // @types-expect-error
      const sortable = new Sortable(el, {
        onEnd(e: any) {
          const { oldIndex, newIndex } = e;
          exchangeArray(cloneColumns.value, oldIndex, newIndex);
          exchangeArray(showColumns.value, oldIndex, newIndex);
        }
      });
    });
  }
};

const handleChange = (checked: boolean | (string | boolean | number)[], column: Column, index: number) => {
  if (!checked) {
    cloneColumns.value = showColumns.value.filter(item => item.dataIndex !== column.dataIndex);
  } else {
    cloneColumns.value.splice(index, 0, column);
  }
};

watch(deptName, newVal => {
  if (!newVal) {
    filteredTreeData.value = deptOptions.value;
  } else {
    filteredTreeData.value = searchData(newVal);
  }
});

watch(
  () => columns.value,
  val => {
    cloneColumns.value = cloneDeep(val);
    cloneColumns.value.forEach((item, _index) => {
      item.checked = true;
    });
    showColumns.value = cloneDeep(cloneColumns.value);
  },
  { deep: true, immediate: true }
);

watch(
  () => queryParams.value.pageNum,
  newPageNum => {
    pagination.value.pageNum = newPageNum;
  }
);

watch(
  () => queryParams.value.pageSize,
  newPageSize => {
    pagination.value.pageSize = newPageSize;
  }
);

onMounted(() => {
  getTreeSelect(); // 初始化部门数据
  getList(); // 初始化列表数据
});
</script>
<style lang="less" scoped>
:deep(.arco-tree-node-title-text) {
  width: 100%;
  white-space: nowrap;
}

:deep(.arco-tree-node) {
  line-height: normal;
  border-radius: var(--border-radius-medium);

  &:hover {
    background-color: var(--color-secondary-hover);
  }

  .arco-tree-node-title {
    &:hover {
      background-color: transparent;
    }
  }
}

:deep(.arco-tree-node-selected) {
  font-weight: bold;
  background-color: rgba(var(--primary-6), 0.1);

  &:hover {
    background-color: rgba(var(--primary-6), 0.1);
  }
}

.action-icon {
  margin-left: 12px;
  cursor: pointer;
}

.active {
  color: #0960bd;
  background-color: #e3f4fc;
}

.setting {
  display: flex;
  align-items: center;
  width: 95px;
  font-size: 12px;

  .title {
    margin-left: 12px;
    cursor: pointer;
  }
}
</style>
